package com.coai.message.service

import com.coai.common.exception.ResourceNotFoundException
import com.coai.common.exception.ValidationException
import com.coai.message.dto.*
import com.coai.message.model.*
import com.coai.message.repository.*
import org.springframework.data.domain.PageRequest
import org.springframework.messaging.simp.SimpMessagingTemplate
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime

@Service
class MessageService(
    private val messageRepository: MessageRepository,
    private val conversationRepository: ConversationRepository,
    private val participantRepository: ConversationParticipantRepository,
    private val readStatusRepository: MessageReadStatusRepository,
    private val messagingTemplate: SimpMessagingTemplate
) {
    
    /**
     * 发送消息
     */
    @Transactional
    fun sendMessage(request: SendMessageRequest, senderId: String): MessageDto {
        // 验证用户是否在会话中
        val participant = participantRepository.findByConversationIdAndUserId(
            request.conversationId, senderId
        ) ?: throw ValidationException("您不在该会话中")
        
        // 创建消息
        val message = Message(
            conversationId = request.conversationId,
            senderId = senderId,
            messageType = request.messageType,
            content = request.content,
            metadata = request.metadata?.let { serializeMetadata(it) },
            replyToId = request.replyToId
        )
        
        val savedMessage = messageRepository.save(message)
        
        // 更新会话的最后消息信息
        updateConversationLastMessage(request.conversationId, savedMessage)
        
        // 转换为DTO
        val messageDto = savedMessage.toDto(senderId)
        
        // 推送消息给会话中的其他用户
        pushMessageToParticipants(request.conversationId, messageDto, senderId)
        
        return messageDto
    }
    
    /**
     * 获取会话消息列表（分页）
     */
    fun getMessages(
        conversationId: String,
        userId: String,
        beforeTime: LocalDateTime? = null,
        limit: Int = 20
    ): MessageListResponse {
        // 验证用户权限
        if (!participantRepository.existsByConversationIdAndUserId(conversationId, userId)) {
            throw ValidationException("您不在该会话中")
        }
        
        val pageable = PageRequest.of(0, limit + 1)
        
        val messages = if (beforeTime != null) {
            messageRepository.findByConversationIdBeforeTime(conversationId, beforeTime, pageable)
        } else {
            messageRepository.findByConversationIdOrderByCreatedAtDesc(conversationId, pageable)
        }
        
        val hasMore = messages.size > limit
        val resultMessages = if (hasMore) messages.take(limit) else messages
        
        // 获取已读状态
        val messageDtos = resultMessages.map { msg ->
            val readBy = readStatusRepository.findUserIdsByMessageId(msg.id!!)
            msg.toDto(userId, readBy)
        }
        
        val nextCursor = if (hasMore && resultMessages.isNotEmpty()) {
            resultMessages.last().createdAt.toString()
        } else null
        
        return MessageListResponse(
            messages = messageDtos,
            hasMore = hasMore,
            nextCursor = nextCursor
        )
    }
    
    /**
     * 标记消息为已读
     */
    @Transactional
    fun markMessagesAsRead(conversationId: String, messageIds: List<String>, userId: String) {
        // 验证权限
        if (!participantRepository.existsByConversationIdAndUserId(conversationId, userId)) {
            throw ValidationException("您不在该会话中")
        }
        
        messageIds.forEach { messageId ->
            val message = messageRepository.findById(messageId).orElse(null) ?: return@forEach
            
            // 不能标记自己发送的消息为已读
            if (message.senderId == userId) return@forEach
            
            // 检查是否已读
            if (!readStatusRepository.existsByMessageIdAndUserId(messageId, userId)) {
                readStatusRepository.save(
                    MessageReadStatus(
                        messageId = messageId,
                        userId = userId
                    )
                )
                
                // 通知发送者消息已读
                notifyMessageRead(message, userId)
            }
        }
    }
    
    /**
     * 标记会话所有消息为已读
     */
    @Transactional
    fun markConversationAsRead(conversationId: String, userId: String) {
        readStatusRepository.markAllAsRead(conversationId, userId)
        
        // 推送已读通知
        messagingTemplate.convertAndSendToUser(
            userId,
            "/queue/read-status",
            mapOf(
                "conversationId" to conversationId,
                "unreadCount" to 0
            )
        )
    }
    
    /**
     * 撤回消息
     */
    @Transactional
    fun recallMessage(messageId: String, userId: String): MessageDto {
        val message = messageRepository.findById(messageId)
            .orElseThrow { ResourceNotFoundException("消息不存在") }
        
        // 只能撤回自己发送的消息
        if (message.senderId != userId) {
            throw ValidationException("只能撤回自己发送的消息")
        }
        
        // 检查是否超过2分钟
        if (message.createdAt!!.plusMinutes(2).isBefore(LocalDateTime.now())) {
            throw ValidationException("只能撤回2分钟内的消息")
        }
        
        message.recalled = true
        message.recalledAt = LocalDateTime.now()
        val updated = messageRepository.save(message)
        
        // 通知会话中的所有用户
        val notification = MessageNotification(
            action = "MESSAGE_RECALLED",
            message = updated.toDto(userId),
            conversationId = message.conversationId,
            unreadCount = null
        )
        
        messagingTemplate.convertAndSend(
            "/topic/conversation/${message.conversationId}",
            notification
        )
        
        return updated.toDto(userId)
    }
    
    /**
     * 搜索消息
     */
    fun searchMessages(
        conversationId: String,
        keyword: String,
        userId: String,
        limit: Int = 50
    ): List<MessageDto> {
        // 验证权限
        if (!participantRepository.existsByConversationIdAndUserId(conversationId, userId)) {
            throw ValidationException("您不在该会话中")
        }
        
        val pageable = PageRequest.of(0, limit)
        val messages = messageRepository.searchByKeyword(conversationId, keyword, pageable)
        
        return messages.map { it.toDto(userId) }
    }
    
    /**
     * 获取未读消息数
     */
    fun getUnreadCount(conversationId: String, userId: String): Long {
        return messageRepository.countUnreadMessages(conversationId, userId)
    }
    
    // 辅助方法
    
    private fun updateConversationLastMessage(conversationId: String, message: Message) {
        val conversation = conversationRepository.findById(conversationId).orElse(null) ?: return
        
        conversation.lastMessageId = message.id
        conversation.lastMessageTime = message.createdAt
        conversation.lastMessageContent = when (message.messageType) {
            MessageType.TEXT -> message.content
            MessageType.IMAGE -> "[图片]"
            MessageType.FILE -> "[文件]"
            MessageType.VOICE -> "[语音]"
            MessageType.VIDEO -> "[视频]"
            MessageType.LOCATION -> "[位置]"
            MessageType.CARD -> "[卡片]"
            MessageType.SYSTEM -> message.content
        }
        
        conversationRepository.save(conversation)
    }
    
    private fun pushMessageToParticipants(
        conversationId: String,
        message: MessageDto,
        senderId: String
    ) {
        // 获取会话中的其他参与者
        val otherParticipantIds = participantRepository.findOtherParticipantIds(
            conversationId, senderId
        )
        
        // 推送到会话topic
        val notification = MessageNotification(
            action = "NEW_MESSAGE",
            message = message,
            conversationId = conversationId,
            unreadCount = null
        )
        
        messagingTemplate.convertAndSend(
            "/topic/conversation/$conversationId",
            notification
        )
        
        // 为每个参与者推送未读数
        otherParticipantIds.forEach { userId ->
            val unreadCount = getUnreadCount(conversationId, userId)
            messagingTemplate.convertAndSendToUser(
                userId,
                "/queue/unread",
                mapOf(
                    "conversationId" to conversationId,
                    "unreadCount" to unreadCount
                )
            )
        }
    }
    
    private fun notifyMessageRead(message: Message, readByUserId: String) {
        messagingTemplate.convertAndSendToUser(
            message.senderId,
            "/queue/read-status",
            mapOf(
                "messageId" to message.id,
                "conversationId" to message.conversationId,
                "readByUserId" to readByUserId,
                "readAt" to LocalDateTime.now()
            )
        )
    }
    
    private fun serializeMetadata(metadata: Map<String, Any>): String {
        // TODO: 使用Jackson序列化
        return "{}"
    }
    
    private fun Message.toDto(
        currentUserId: String,
        readBy: List<String> = emptyList()
    ): MessageDto {
        return MessageDto(
            id = id!!,
            conversationId = conversationId,
            senderId = senderId,
            senderName = null, // TODO: 从用户服务获取
            senderAvatar = null,
            messageType = messageType,
            content = content,
            metadata = null, // TODO: 反序列化metadata
            replyTo = null, // TODO: 如果有replyToId，查询原消息
            readBy = readBy,
            recalled = recalled,
            createdAt = createdAt!!
        )
    }
}
